<?php

/**
 * 参数校验类
 */
class LParamCheckFilter extends CFilter
{

    private $_rules = array();
    private $_actions = array();

    private $_requestType = '';

    public function getRules()
    {
        return $this->_rules;
    }

    /**
     * 参数校验
     */
    public function getActionRules($action)
    {
        $action = strtolower($action->id);
        return isset($this->_rules[$action]) ? $this->_rules[$action] : array();
    }

    public function setRules($rules)
    {
        if(!empty($rules))
        {
            $rules = array_change_key_case($rules);
            $this->_actions = array_keys($rules);
            foreach ($rules as $action => $actionRules)
            {
                foreach ($actionRules as $name => $rule)
                {
                    if(strtoupper($name) == "REQUEST_TYPE")
                    {
                        $this->_rules[$action][strtoupper($name)] = $rule;
                        continue;
                    }

                    $pr = new LParamRule();
                    $pr->setRule($rule);
                    $this->_rules[$action][$name] = $pr;
                }
            }
        }

    }

    /**
     * 返回json
     */
    protected function sendJson($errno, $errmsg)
    {
        header("Content-type:application/json; charset=utf-8");
        echo json_encode(array('errno' => $errno, 'errmsg' => $errmsg, 'data' => array()));
        Yii::app()->end();
    }


    protected function preFilter($filterChain)
    {
        $app = Yii::app();
        $request=$app->getRequest();
        $controller = $filterChain->controller;
        $action = $filterChain->action;
        $actionRules = $this->getActionRules($action);
        if(isset($actionRules['REQUEST_TYPE']))
        {
            $requestType = strtoupper($actionRules['REQUEST_TYPE']);
             if($requestType != $request->getRequestType())
             {
                $this->sendJson('403', '该方法不能够被允许');
                return false;
             }

            unset($actionRules['REQUEST_TYPE']);
        }

        if(!empty($actionRules))
        {
            foreach ($actionRules as $name => $rule)
            {
                $v = $request->getParam($name);

                if(!$rule->isVerified($v, $controller))
                {
                    $this->sendJson($rule->getErrNo(), $rule->getErrMsg());
                }
            }

            return true;

        }else{
            return true;
        }
    }

}

class LParamRule extends CComponent
{
    private $_rule = array();

    /**
     *
     *array(
            'type' => 'String',//默认String, int|string|enum|url|email
            'enum' => false,//枚举所在的字段集合
            'need' => false,//默认false
            'range_length' => false,//字符长度范围,默认false
            'range_szie' => false,//数字大小的范围，默认false
            '__errmsg'=>'参数不合法',//默认提示: 参数不合法
            '__errno' => 10001,//错误码，默认10001
            );
     *
     */
    public function setRule($rule)
    {
        $this->_rule = $rule;
    }

    public function getType()
    {
        return isset($this->_rule['type']) ? strtoupper($this->_rule['type'] ): '';
    }

    /**
     * @param $value 前端传递过来的值
     * @param $p 调用的类，用于支持自定义的方法
     */
    public function isVerified($value, $p)
    {
        $rule = $this->_rule;
        if(empty($rule))
        {
            return true;
        }

        $defaultRule = array(
            'type' => 'String',//默认String, int|string|enum
            'enum' => false,//枚举所在的字段集合
            'need' => false,//默认false
            'range_length' => false,//字符长度范围@link StringUtil::strLength,默认false
            'range_size' => false,//数字大小的范围，默认false
            '__errmsg'=>'您的输入有误，请刷新页面后重试',//默认提示: 参数不合法
            '__errno' => 10001,//错误码，默认10001
            );

        $rule = array_merge($defaultRule, $rule);
        $this->_rule = $rule;
        $type = $rule['type'];
        if($this->commonVerify($value))
        {
             if(empty($value))
            {
                return true;
            }


            if('METHOD' == $this->getType() && isset($rule['method']))
            {
                return call_user_func(array($p, $rule['method']), $value);
            }
            $method ="verify".ucfirst(strtolower($type));
            return call_user_func(array($this, $method), $value);
        }else{
            Yii::trace("common verify failed");
            return false;
        }

    }


    private function verifyInt($value)
    {
        if(!is_numeric($value))
        {
            return false;
        }

        if(false === $range = $this->_rule['range_size'])
        {
            return true;
        }

        if($range[0] <= $value && $range[1] >= $value)
        {
            return true;
        }else{
            return false;
        }
    }

    private function verifyEmail($value)
    {
        $va = new CEmailValidator();
        return $va->validateValue($value);
    }


    private function verifyString($value)
    {
        if(!is_string($value))
        {
            return false;
        }

        if(false === $range = $this->_rule['range_length'])
        {
            return true;
        }
        $strLen = $this->strLength($value);

        if($range[0] <= $strLen && $range[1] >= $strLen)
        {
            return true;
        }else{
            Yii::trace("string length failed , length is " . $strLen);
            return false;
        }
    }

    private function commonVerify($value)
    {
        if(is_null($value) && $this->_rule["need"])
        {
            return false;
        }

        return true;
    }

    private function verifyUrl($value)
    {
        if(strlen($value) >= 250)
        {
            return false;
        }

        $va = new CUrlValidator();
        return $va->validateValue($value);
    }

    private function verifyArray($value)
    {
        if(!is_array($value))
        {
            return false;
        }

        return true;
    }

    private function verifyEnum($value)
    {

        if(empty($this->_rule["enum"]))
        {
            throw new CHttpException(500, "枚举类型参数配置错误");
        }

        if(!in_array($value, $this->_rule["enum"]))
        {
            return false;
        }else{
            return true;
        }

    }

    /**
     * 中文占俩个字符，英文占一个字符
     */
    private function strLength($str, $trim = true)
    {
        $trim && $str = trim($str);
        $bl = strlen($str);
        $sl = mb_strlen($str, "UTF-8");
        $result = $bl - ($bl - $sl) / 2;
        return intval($result);
    }

    /**
     * 获取错误信息
     */
    public function getErrMsg()
    {
        return $this->_rule["__errmsg"];
    }

    /**
     * 获取状态吗
     */
    public function getErrNo()
    {
        return $this->_rule["__errno"];
    }

}